package com.tenbent.product.base.bo;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.tenbent.product.base.enums.error.ErrorEnum;
import com.tenbent.product.base.exception.TenbentException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 *
 *
 * 实体对象基类
 *
 * @author Randy Yan
 * 
 *         实体对象基类，公用的一些属性
 * 
 *         Created by ThinkPad on 2017/7/25.
 *
 */
public class BizObject implements Serializable {

	/** 实体对象ID **/
	@Id
	private Integer id;

	/** 实体对象删除标识 **/
	@Column(name = "del_flag")
	private Integer delFlag;

	/** 实体对象创建人ID **/
	@Column(name = "create_id")
	private Integer createId;

	/** 实体对象修改人ID **/
	@Column(name = "modify_id")
	private Integer modifyId;

	/** 实体对象创建日期 **/
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	@Column(name = "gmt_created")
	private Date createDate;

	/** 实体对象修改人ID **/
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	@Column(name = "gmt_modified")
	private Date modifyDate;

	public BizObject() {

	}

	/**
	 * 用于存放POJO的列信息
	 */
	private transient static Map<Class<? extends BizObject>, List<String>> columnMap = new HashMap<>();

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getDelFlag() {
		return delFlag;
	}

	public void setDelFlag(Integer delFlag) {
		this.delFlag = delFlag;
	}

	public Integer getCreateId() {
		return createId;
	}

	public void setCreateId(Integer createId) {
		this.createId = createId;
	}

	public Integer getModifyId() {
		return modifyId;
	}

	public void setModifyId(Integer modifyId) {
		this.modifyId = modifyId;
	}

	public Date getCreateDate() {
		return createDate;
	}

	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}

	public Date getModifyDate() {
		return modifyDate;
	}

	public void setModifyDate(Date modifyDate) {
		this.modifyDate = modifyDate;
	}

	public static Map<Class<? extends BizObject>, List<String>> getColumnMap() {
		return columnMap;
	}

	public static void setColumnMap(Map<Class<? extends BizObject>, List<String>> columnMap) {
		BizObject.columnMap = columnMap;
	}

	/**
	 * 获取POJO对应的表名 需要POJO中的属性定义@Table(name)
	 * 
	 * @return
	 */
	public String tablename() throws TenbentException {

		Table table = this.getClass().getAnnotation(Table.class);
		if (table != null)
			return table.name();
		else
			throw new TenbentException(ErrorEnum.DATA.getValue(), "undefine POJO @Table, need Tablename(@Table(name))");
	}

	/**
	 * 获取POJO中的主键字段名 需要定义@Id
	 * 
	 * @return
	 */
	public String id() throws TenbentException {
		for (Field field : this.getClass().getDeclaredFields()) {
			if (field.isAnnotationPresent(Id.class))
				return field.getName();
		}
		for (Field field : this.getClass().getSuperclass().getDeclaredFields()) {

			if (field.isAnnotationPresent(Id.class))
				return field.getName();
		}
		throw new TenbentException(ErrorEnum.DATA.getValue(), "undefine POJO @Id");
	}

	// 用于判断filed 方式的字段
	private boolean isNull(String fieldname) {
		try {
			Field field = this.getClass().getDeclaredField(fieldname);
			return isNull(field);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			return isSupFieldNull(fieldname);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
		return false;
	}

	// 用于判断filed 方式的字段
	private boolean isSupFieldNull(String fieldname) {
		try {
			Field field = this.getClass().getSuperclass().getDeclaredField(fieldname);
			return isNull(field);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
		return false;
	}

	private boolean isNull(Field field) {
		try {
			field.setAccessible(true);
			return field.get(this) == null;
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

		return false;
	}

	/**
	 * 用于计算类定义 需要POJO中的属性定义@Column(name) 如果 @Column 有name 则安 column 算列名,如果没有安属性
	 * 算列名
	 */
	public void caculationColumnList() {
		if (columnMap.containsKey(this.getClass()))
			return;

		Field[] fields = this.getClass().getDeclaredFields();
		Field[] supFields = this.getClass().getSuperclass().getDeclaredFields();
		List<String> columnList = new ArrayList<>(fields.length * supFields.length);

		for (Field field : fields) {
			if (field.isAnnotationPresent(Column.class)) {
				columnList.add(field.getName());
			}
		}
		for (Field field : supFields) {
			if (field.isAnnotationPresent(Column.class)) {
				columnList.add(field.getName());
			}
		}
		columnMap.put(this.getClass(), columnList);
	}

	/**
	 * 获取用于WHERE的 有值字段表
	 * 
	 * @return
	 */
	public List<WhereColumn> returnWhereColumnsName() {
		Field[] fields = this.getClass().getDeclaredFields();
		Field[] supFields = this.getClass().getSuperclass().getDeclaredFields();
		Field[] allFields = ArrayUtils.addAll(fields, supFields);
		List<WhereColumn> columnList = new ArrayList<>(allFields.length);
		for (Field field : allFields) {
			if (field.isAnnotationPresent(Id.class) && !isNull(field)) {
				columnList.add(
						new WhereColumn(field.getName(), field.getName(), field.getGenericType().equals(String.class)));
			}
			if (field.isAnnotationPresent(Column.class) && !isNull(field)) {
				// 获取属性上的指定类型的注解
				String fieldName = getAnnotationFieldName(field);
				columnList
						.add(new WhereColumn(fieldName, field.getName(), field.getGenericType().equals(String.class)));
			}
		}
		return columnList;
	}

	/**
	 * 用于获取Insert的字段累加
	 * 
	 * @return
	 */
	public String returnInsertColumnsName() {
		StringBuilder sb = new StringBuilder();
		List<String> list = columnMap.get(this.getClass());
		int i = 0;
		for (String column : list) {
			if (isNull(column)) {
				continue;
			}
			if (i++ != 0) {
				sb.append(',');
			}
			setFieldColumn(sb, column);
		}
		return sb.toString();
	}

	/**
	 * 用于获取Insert的字段值映射累加
	 * 
	 * @return
	 */
	public String returnInsertColumnsDefine() {
		StringBuilder sb = new StringBuilder();
		List<String> list = columnMap.get(this.getClass());
		int i = 0;
		for (String column : list) {
			if (isNull(column))
				continue;

			if (i++ != 0)
				sb.append(',');
			sb.append("#{").append(column).append('}');
		}
		return sb.toString();
	}

	/**
	 * 用于获取Update Set的字段累加
	 * 
	 * @return
	 */
	public String returnUpdateSet() {
		StringBuilder sb = new StringBuilder();

		List<String> list = columnMap.get(this.getClass());
		int i = 0;
		for (String column : list) {
			if (isNull(column))
				continue;

			if (i++ != 0) {
				sb.append(',');
			}
			setFieldColumn(sb, column);
			sb.append("=#{").append(column).append('}');
		}
		return sb.toString();
	}

	public String getAnnotationFieldName(Field field) {
		String fieldName = field.getName();
		if (field.isAnnotationPresent(Column.class)) {
			Annotation annotation = field.getAnnotation(Column.class);
			Column column = (Column) annotation;
			fieldName = StringUtils.isNotEmpty(column.name()) ? column.name() : fieldName;
		}
		return fieldName;
	}

	@Override
	public String toString() {
		Field[] fields = this.getClass().getDeclaredFields();
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for (Field f : fields) {
			if (Modifier.isStatic(f.getModifiers()) || Modifier.isFinal(f.getModifiers()))
				continue;
			Object value = null;
			try {
				f.setAccessible(true);
				value = f.get(this);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			if (value != null)
				sb.append(f.getName()).append('=').append(value).append(',');
		}
		sb.append(']');

		return sb.toString();
	}

	/**
	 * Where条件信息
	 * 
	 * @author HUYAO
	 * 
	 */
	public class WhereColumn {
		public String name;
		public boolean isString;
		public String valueName;

		public WhereColumn(String name, String valueName, boolean isString) {
			this.name = name;
			this.valueName = valueName;
			this.isString = isString;
		}
	}

	/**
	 * 
	 * 深度克隆 前提对象实现了Serializable
	 * 
	 */
	public Object deepClone() throws IOException, OptionalDataException, ClassNotFoundException {
		// 将对象写到流里
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		ObjectOutputStream oo = new ObjectOutputStream(bo);
		oo.writeObject(this);
		// 从流里读出来
		ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
		ObjectInputStream oi = new ObjectInputStream(bi);
		return (oi.readObject());
	}

	private void setFieldColumn(StringBuilder sb, String column) {
		try {
			Field field = this.getClass().getDeclaredField(column);
			setFieldColum(field, column, sb);
		} catch (NoSuchFieldException e) {
			setSupFieldColumn(sb, column);
		} catch (SecurityException e) {
			e.printStackTrace();
		}
	}

	private void setSupFieldColumn(StringBuilder sb, String column) {
		try {
			Field field = this.getClass().getSuperclass().getDeclaredField(column);
			setFieldColum(field, column, sb);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
	}

	private void setFieldColum(Field field, String column, StringBuilder sb) {
		if (field.isAnnotationPresent(Column.class)) {
			Column col = field.getAnnotation(Column.class);
			String columnName = col.name();
			if (StringUtils.isNotEmpty(columnName)) {
				sb.append(columnName);
			} else {
				sb.append(column);
			}
		}
	}

}
